<?php
namespace Sfsn\Core\Model;

use Sfsn\Core\Config;
use Sfsn\Core\Http\Request;

class Model
{

    /**
     * 数据
     *
     * @var unknown
     */
    public $data = null;

    /**
     * 错误信息
     *
     * @var unknown
     */
    public $error = [];

    /**
     * 数据连接
     *
     * @var unknown
     */
    public $dbConfig = [];

    public static $query;
    /**
     * 表名
     *
     * @var unknown
     */
    public $tableName = '';

    /**
     * 开启表前缀
     *
     * @var unknown
     */
    public $prefix = true;

    /**
     * 验证规则
     * 'required'=>true, //必须输入的字段。
     * 'email'=>true, //必须输入正确格式的电子邮件。
     * 'url'=>true, //必须输入正确格式的网址。
     * 'date'=>true, //必须输入正确格式的日期。日期校验。
     * 'dateISO'=>true, //必须输入正确格式的日期（ISO），例如：2009-06-23，1998/01/22。只验证格式，不验证有效性。
     * 'number'=>true, //必须输入合法的数字（负数，小数）。
     * 'integer'=>true, //必须输入整数。
     * 'double'=>true, //double类型
     * 'english'=>true, //必须输入合法的信用卡号。
     * 'unique'=>true,//验证数据唯一性
     * 'equalTo'=>"field", 输入值必须和 #field 相同。
     * 'accept'=>'', //输入拥有合法后缀名的字符串（上传文件的后缀）。
     * 'maxlength'=>5, //输入长度最多是 5 的字符串（汉字算一个字符）。
     * 'minlength'=>10, //输入长度最小是 10 的字符串（汉字算一个字符）。
     * 'rangelength'=>[5,10], //输入长度必须介于 5 和 10 之间的字符串（汉字算一个字符）。
     * 'range'=>[5,10], //输入值必须介于 5 和 10 之间。
     * 'max'=>5, //输入值不能大于 5。
     * 'min'=>10,
     * 'regex'=>'/^\d{6}$/', //正则表达式
     * 'callback'=>'func',//回调可以是函数或方法'callback'=>['object','func']
     * 实例
     * $rules = [
     * 'field'=>['required','email','range'=>[5,10],'number'],
     * 'field2'=>['required','email','range'=>[5,10],'number'],
     * ];
     */
    public $rules = [];
    /**
     * 默认值
     * @var unknown
     */
    public $custom =[];
    /**
     * 全局处理
     * 会将除自定义（$custom）之外的所有输入的数据进行,可以是函数也可以是类的方法，通过call_user_func调用
     * @var unknown
     */
    public $filter = '';
    /**
     * 错误信息
     * 实例
     * $message = [
     * 'field'=>[
     * 'required'=>'请填写field',
     * 'email'=>'请填写正确的邮箱格式',
     * 'range'=>'输入值必须介于 5 和 10 之间',
     * ],
     * 'field2'=>[
     * 'required'=>'请填写field2',
     * 'email'=>'请填写正确的邮箱格式',
     * 'range'=>'输入值必须介于 5 和 10 之间',
     * ],
     * ];
     *
     * @var unknown
     */
    public $message = [];
    
    /**
     * 实现静态化实例对象
     *
     * @param unknown $method            
     * @param unknown $args            
     * @return mixed
     */
    public static function __callstatic($method, $args)
    {
        $instance = new static();
        return call_user_func_array(array(
            $instance,
            $method
        ), $args);
    }

    /**
     * 回调方法，调用query类实现查询
     *
     * @param unknown $method            
     * @param unknown $args            
     * @return mixed
     */
    public function __call($method, $args)
    {
        
        /**
         * 实例化对象
         */
        $query = $this->newQuery();
        /**
         * 设置数据
         */
        $query->data($this->formData());
        /**
         * 执行对象实例和方法
         */
        return call_user_func_array(array(
            $query,
            $method
        ), $args);
    }
    
    public function __get($key)
    {
        return isset($this->data[$key]) ? $this->data[$key] : null;
    }
    public function __set($key,$value)
    {
        $this->data[$key] = $value;
    }
    /**
     * 建立数据库对象
     *
     * @return \Sfsn\Core\Model\Query
     */
    public function newQuery()
    {
        $config = $this->dbConfig();
        self::$query = new Query($config);
        /**
         * 表名
         */
        $tableName = $this->tableName(); // 表名
        /**
         * 表前缀开关
         */
        $prefix = $this->prefix;
        /**
         * 设置表
         */
        self::$query->table($tableName, $prefix);
        return self::$query;
    }

    /**
     * 获得最近一次的查询语句
     */
    public static function getSql()
    {
        return self::$query->getSql();
    }

    /**
     * 是否开启表前缀默认开启
     *
     * @return \Sfsn\Core\Model\unknown
     */
    public function prefix()
    {
        return $this->prefix;
    }

    /**
     * 获取表名
     *
     * @return Ambigous <string, string>
     */
    public function tableName()
    {
        $table = '';
        if (empty($this->tableName)) {
            $class = get_called_class();
            $table = basename($class);
        } else {
            $table = $this->tableName;
        }
        return $table;
    }

    /**
     * 获取数据连接配置
     *
     * @return Ambigous <multitype:, array, \Sfsn\Core\Model\unknown>
     */
    public function dbConfig()
    {
        $config = [];
        if (empty($this->dbConfig)) {
            $default = Config::get('DB');
            $diy = Config::get('APP');
            $config = array_merge($default, $diy);
        } else {
            $config = $this->dbConfig;
        }
        return $config;
    }

    /**
     * 数据验证
     *
     * @param string $data            
     * @param string $rules            
     * @return \Sfsn\Core\Model\Model
     */
    public function validate($data = null, $rules = null, $message = null)
    {
        // 设置数据
        $this->formData($data);
        $this->message = is_null($message) ? $this->message() : $message;
        // 验证规则设置
        if (is_null($rules))
            $rules = $this->rules();        
            // 循环验证
        foreach ($rules as $field => $rule) {
            $this->validation($field, $rule);
        }
        return $this;
    }

    /**
     * 对每条数据进行验证
     *
     * @param unknown $field            
     * @param unknown $rule            
     */
    public function validation($field, $rule = [])
    {
        $regex = array(
            // 必填
            'required' => '/.+/',
            // 邮箱
            'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
            // 网址
            'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
            // 日期正则
            'date' => '^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$',
            // 货币金额
            'currency' => '/^\d+(\.\d+)?$/',
            // 数字
            'number' => '/^\d+$/',
            // int类型
            'integer' => '/^[-\+]?\d+$/',
            // double类型
            'double' => '/^[-\+]?\d+(\.\d+)?$/',
            // 英文字符
            'english' => '/^[A-Za-z]+$/'
        );
        
        $error = [];
        $data = $this->formData();
        $ruleData = $data[$field];
        $message = $this->message[$field];
        
        foreach ($rule as $name => $args) {
            if (is_numeric($name)) {
                // 类型验证，无参数，主要有require,email,url,date,currency,number,integer,double,english,unique
                
                // 内置正则验证
                if (array_key_exists($args, $regex)) {
                    if (! preg_match($regex[$args], $ruleData)) {
                        $this->error[] = [
                            'message' => $message[$args], // 错误信息
                            'field' => $field, // 出错字段
                            'rule' => $args
                        ]; // 验证规则
                        
                        continue;
                    }
                }
                // 验证数据唯一性
                if ($args == 'unique') {
                    $where = [
                        $field => $ruleData
                    ];
                    $row = $this->newQuery()
                        ->where($where)
                        ->fetch();
                    if ($row) {
                        $this->error[] = [
                            // 错误信息
                            'message' => $message[$args],
                            // 出错字段
                            'field' => $field,
                            // 验证规则
                            'rule' => $args
                        ];
                        continue;
                    }
                }
            } else {
                // 带参数的验证
                switch ($name) {
                    case 'equalTo': // 输入值必须和 field 相同。
                        if ($ruleData != $data[$args]) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        
                        break;
                    case 'maxlength': // 输入长度最多是 5 的字符串（汉字算一个字符）。
                        if (mb_strlen($ruleData, 'utf-8') > $args) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'minlength': // 输入长度最小是 10 的字符串（汉字算一个字符）。
                        if (mb_strlen($ruleData, 'utf-8') < $args) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'rangelength': // 输入长度必须介于 5 和 10 之间的字符串（汉字算一个字符）。
                        $len = mb_strlen($ruleData, 'utf-8');
                        if ($len < $args[0] || $len > $args[1]) {
                            
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        
                        break;
                    case 'range': // 输入值必须介于 5 和 10 之间。
                        if ($ruleData < $args[0] || $ruleData > $args[1]) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'max': // 输入值不能大于 5。
                        if ($ruleData > $args) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'min': // 输入值不能小于 5。
                        if ($ruleData < $args) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'regex': // 正则表达式
                        if (! preg_match($ruleData, $args)) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                        break;
                    case 'callback': // 函数或方法
                        if (! call_user_func($args, $ruleData)) {
                            $error = [
                                // 错误信息
                                'message' => $message[$name],
                                // 出错字段
                                'field' => $field,
                                // 验证规则
                                'rule' => $name
                            ];
                        }
                } // switch $name结束
                  
                // 如果发现错误则进行赋值
                if ($error) {
                    $this->error[] = $error;
                    $error = [];
                }
            }
        } // foreach 结束
    }

    /**
     * 获取验证规则
     *
     * @return multitype:
     */
    public function rules()
    {
        return $this->rules;
    }
    /**
     * 自定义数据
     * @return \Sfsn\Core\Model\unknown
     */
    public function custom()
    {
        return $this->custom;
    }
    /**
     * 全局过滤
     * @return \Sfsn\Core\Model\unknown
     */
    public function filter()
    {
        return $this->filter;
    }
    /**
     * 获取错误提示
     *
     * @return \Sfsn\Core\Model\unknown
     */
    public function message()
    {
        return $this->message;
    }

    
    /**
     * 设置和获取数据
     *
     * @param string $data            
     * @return Ambigous <string, \Sfsn\Core\Http\Ambigous>
     */
    public function formData($data = null)
    {
        //获得默认值
        $output = $this->custom();   
        //自动过滤
        $filter = $this->filter();     
        //处理数据
        is_null($data) && $data = Request::post();    
        if(!empty($data)){ 
            foreach ($data as $key=>$val){
                //全局过滤处理
                $output[$key] = $filter ? call_user_func($filter,$val) : $val;
            } 
        }       
        $this->data = $output;
        return $this->data;
    }

    /**
     * 返回错误
     * $complete true时返回完整 默认false只返回错误信息
     * @param string $complete
     * @return multitype:\Sfsn\Core\Model\unknown |\Sfsn\Core\Model\unknown
     */
    public function getError($complete = false)
    {
        //简单返回，只返回错误信息
        if(!$complete){
            $error = [];
            foreach ($this->error as $val){
                $error[] = $val['message'];
            }
            return $error;
        }
        //返回所有内容包括错误信息，字段，验证规则
        return $this->error;
    }
}

